package com.new4net.exe_stream.instruction.impl;

import com.new4net.exe_stream.meta.ExecutionContext;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;

public class WhileInstruction<R> extends AbstractInstruction {
    protected Consumer<ExecutionContext.InstructionContext> initor;
    protected Predicate<ExecutionContext.InstructionContext> predicate;
    protected Function<ExecutionContext.InstructionContext,R> body;

    protected List<ExecutionContext.InstructionContext> instructionContexts
            = new ArrayList<>();


    public WhileInstruction(String instructionName, Consumer<ExecutionContext.InstructionContext> consumer, Predicate<ExecutionContext.InstructionContext> predicate, Function<ExecutionContext.InstructionContext, R> body) {
        super(instructionName);
        this.instructionName = instructionName;
        this.predicate = predicate;
        this.body = body;
        this.initor=consumer;
    }




    @Override
    public void exe() {
        initor.accept(instructionContext);
        exeBody();

    }
    private void exeBody() {
        while (predicate.test(instructionContext)){
            retVal=body.apply(instructionContext);
            
            executionContext.addInstructionContext(instructionContext);
            instructionContexts.add(instructionContext);
            instructionContext=executionContext.buildInstructionContext();
        }
    }


    public void retryAll(){

        synchronized (this){
            try {
                retryPrev();
                int i=0;

                while (predicate.test(instructionContext)){
                    boolean flag = false;
                    if(instructionContexts.size()>i){
                        instructionContext=instructionContexts.get(i);
                        instructionContext.clear();
                    }else{
                        instructionContext=executionContext.buildInstructionContext();
                        flag=true;
                    }


                    retVal=body.apply(instructionContext);
                    if(flag){
                        
                        executionContext.addInstructionContext(instructionContext);
                        instructionContexts.add(instructionContext);
                        instructionContext=executionContext.buildInstructionContext();
                    }

                    i++;
                }
                post();
            } catch (Throwable e) {
                fault(e);

            }
        }



    }




    protected void exeRetry() {
        exeBody();
    }
    @Override
    public String getInstuctionType() {
        return "while";
    }


}
